package k8s

import (
	"k8s.io/apimachinery/pkg/labels"
	"sigs.k8s.io/controller-runtime/pkg/event"
	"sigs.k8s.io/controller-runtime/pkg/predicate"
)

// LabelSelectorPredicate creates a predicate that filters resources based on label selector
func LabelSelectorPredicate(labelSelector labels.Selector) predicate.Predicate {
	return predicate.Funcs{
		CreateFunc: func(e event.CreateEvent) bool {
			return labelSelector.Matches(labels.Set(e.Object.GetLabels()))
		},
		UpdateFunc: func(e event.UpdateEvent) bool {
			return labelSelector.Matches(labels.Set(e.ObjectNew.GetLabels()))
		},
		DeleteFunc: func(e event.DeleteEvent) bool {
			return labelSelector.Matches(labels.Set(e.Object.GetLabels()))
		},
		GenericFunc: func(e event.GenericEvent) bool {
			return labelSelector.Matches(labels.Set(e.Object.GetLabels()))
		},
	}
}

// NamespacePredicate creates a predicate that filters resources based on namespace
func NamespacePredicate(namespace string) predicate.Predicate {
	return predicate.Funcs{
		CreateFunc: func(e event.CreateEvent) bool {
			return e.Object.GetNamespace() == namespace
		},
		UpdateFunc: func(e event.UpdateEvent) bool {
			return e.ObjectNew.GetNamespace() == namespace
		},
		DeleteFunc: func(e event.DeleteEvent) bool {
			return e.Object.GetNamespace() == namespace
		},
		GenericFunc: func(e event.GenericEvent) bool {
			return e.Object.GetNamespace() == namespace
		},
	}
}

// ResourceNamePredicate creates a predicate that filters resources based on name pattern
func ResourceNamePredicate(namePattern string) predicate.Predicate {
	return predicate.Funcs{
		CreateFunc: func(e event.CreateEvent) bool {
			return matchesPattern(e.Object.GetName(), namePattern)
		},
		UpdateFunc: func(e event.UpdateEvent) bool {
			return matchesPattern(e.ObjectNew.GetName(), namePattern)
		},
		DeleteFunc: func(e event.DeleteEvent) bool {
			return matchesPattern(e.Object.GetName(), namePattern)
		},
		GenericFunc: func(e event.GenericEvent) bool {
			return matchesPattern(e.Object.GetName(), namePattern)
		},
	}
}

// AndPredicate combines multiple predicates with AND logic
func AndPredicate(predicates ...predicate.Predicate) predicate.Predicate {
	return predicate.Funcs{
		CreateFunc: func(e event.CreateEvent) bool {
			for _, p := range predicates {
				if !p.Create(e) {
					return false
				}
			}
			return true
		},
		UpdateFunc: func(e event.UpdateEvent) bool {
			for _, p := range predicates {
				if !p.Update(e) {
					return false
				}
			}
			return true
		},
		DeleteFunc: func(e event.DeleteEvent) bool {
			for _, p := range predicates {
				if !p.Delete(e) {
					return false
				}
			}
			return true
		},
		GenericFunc: func(e event.GenericEvent) bool {
			for _, p := range predicates {
				if !p.Generic(e) {
					return false
				}
			}
			return true
		},
	}
}

// OrPredicate combines multiple predicates with OR logic
func OrPredicate(predicates ...predicate.Predicate) predicate.Predicate {
	return predicate.Funcs{
		CreateFunc: func(e event.CreateEvent) bool {
			for _, p := range predicates {
				if p.Create(e) {
					return true
				}
			}
			return false
		},
		UpdateFunc: func(e event.UpdateEvent) bool {
			for _, p := range predicates {
				if p.Update(e) {
					return true
				}
			}
			return false
		},
		DeleteFunc: func(e event.DeleteEvent) bool {
			for _, p := range predicates {
				if p.Delete(e) {
					return true
				}
			}
			return false
		},
		GenericFunc: func(e event.GenericEvent) bool {
			for _, p := range predicates {
				if p.Generic(e) {
					return true
				}
			}
			return false
		},
	}
}

// matchesPattern is a helper function to check if a name matches a pattern
// For now, it's a simple string comparison, but could be extended to support regex
func matchesPattern(name, pattern string) bool {
	return name == pattern
}

// CreatePredicateForResource creates a predicate for a specific resource type with label filtering
func CreatePredicateForResource(labelSelector labels.Selector, namespace string) predicate.Predicate {
	predicates := []predicate.Predicate{}

	if labelSelector != nil {
		predicates = append(predicates, LabelSelectorPredicate(labelSelector))
	}

	if namespace != "" {
		predicates = append(predicates, NamespacePredicate(namespace))
	}

	if len(predicates) == 0 {
		return predicate.Funcs{} // No filtering
	}

	if len(predicates) == 1 {
		return predicates[0]
	}

	return AndPredicate(predicates...)
}
